<?php

//used by galleryProduct relationship
Yii::import('application.modules.Gallery.models.*');
/**
 * This is the model class for table "_product".
 */
require_once(dirname(__FILE__) . '/base/ProductBase.php');
/**
 * This is the model class for table "_shop_product".
 *
 * The followings are the available columns in table '_shop_product':
 * @property string $id
 * @property string $name
 * @property string $alias
 * @property string $details1
 * @property string $details2
 * @property string $details3
 * @property string $details4
 * @property string $details5
 * @property string $creation_datetime
 * @property string $last_update
 * @property boolean $status
 * @property boolean $custom_url
 * @property boolean $page_details
 * @property boolean $on_sale
 * @property boolean $on_sale_start
 * @property boolean $on_sale_end
 * @property boolean $available_start_date
 * @property boolean $available_end_date
 * @property boolean $bv_review_id
 * @property boolean $sub_default
 */
class Product extends ProductBase
{
    //Use for metatag in page
    public $metaData;
    public $fbMetaData;
    //only use for search form
    public $subproductCriteria;
    public $attrsSelected;
    public $subproductAttrsSelected;
    public $category;

    public $_currentSubproduct;

    //public $price;

    /**
     * @return array relational rules.
     */
    public function relations()
    {
        return array(
            'attrs' => array(self::MANY_MANY, 'Attribute', SITE_ID . '_shop_product_attribute(product_id,attribute_id)'),
            'categories' => array(self::MANY_MANY, 'ProductCategory', SITE_ID . '_shop_product_category(product_id,category_id)'),
            'subProduct' => array(self::HAS_MANY, 'SubProduct', 'product_id'),
            'subProductCount' => array(self::STAT, 'SubProduct', 'product_id'),
            'relationProduct' => array(self::MANY_MANY, 'Product', SITE_ID . '_shop_product_x_relation_product(product_id,product_relation_id)', 'order' => '"relationProduct_relationProduct".ordering'),
            'crossProducts' => array(self::MANY_MANY, 'Product', SITE_ID . '_shop_cross_sale(product_id,cross_sale_id)'),
            'flashCategories' => array(self::MANY_MANY, 'FlashCategory', SITE_ID . '_shop_product_category(product_id,category_id)', 'condition' => 'NOW() BETWEEN start_date AND end_date'),
            'galleryProduct' => array(self::BELONGS_TO, 'Gallery', 'gallery'),
            'attribute_groups' => array(self::MANY_MANY, 'AttributeGroup', SITE_ID . '_shop_product_attribute_group(product_id,attribute_group_id)'),
            'reviews' => array(self::HAS_MANY, 'Review', 'product_id'),
            'reviews_published' => array(self::HAS_MANY, 'Review', 'product_id',
                    'condition' => 'reviews_published.status = ' . Review::STATUS_PUBLISHED,
                    'order' => 'reviews_published.creation_datetime DESC'),
        );
    }

    public function rules()
    {
        return array(
            array('name,alias,details1', 'required'),
            array('name', 'length', 'max' => 1500),
            array('alias', 'length', 'max' => 200),
            array('details2, details3, details4, details5', 'length', 'max' => 5000),
            array('on_sale_start', 'validateSale'),
            array('creation_datetime, last_update, status, custom_url, page_details,on_sale, on_sale_start, on_sale_end, available_start_date, available_end_date,view,category,bv_review_id, sub_default', 'safe'),
            array('creation_datetime', 'default', 'value' => new CDbExpression('NOW()::timestamptz(0)'), 'setOnEmpty' => false, 'on' => 'insert'),
            array('last_update', 'default', 'value' => new CDbExpression('NOW()::timestamptz(0)'), 'setOnEmpty' => false, 'on' => 'insert, update'),
            // The following rule is used by search().
            // Please remove those attributes that should not be searched.
            array('id, name, custom_url, page_details, alias, details1, details2, details3, details4, details5, creation_datetime, last_update, status, in_stock, on_sale, appearance_settings', 'safe', 'on' => 'search'),
        );
    }

    public function validateSale($attribute, $param)
    {
        if ($this->on_sale == true) {
            if (empty($this->on_sale_start)) {
                $this->addError('on_sale_start', 'Sale start date can not be null if on sale is activate');
            } else {
                if (!empty($this->on_sale_end)) {
                    if (strtotime($this->on_sale_end) < strtotime($this->on_sale_start)) {
                        $this->addError('on_sale_end', 'Sale end date must larger than sale start date');
                    }
                }
            }
        }
    }

    /**
     * Retrieves a list of models based on the current search/filter conditions.
     * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
     */
    public function search($merge = null)
    {
        $criteria = new CDbCriteria;
        $criteria->distinct = true;

        $criteria->addSearchCondition('t.name', $this->name, true, 'AND', 'ILIKE');
        $criteria->compare('t.alias', $this->alias, true);
        /*if(!empty($this->status))
            var_dump($this->status);*/
        $criteria->compare('t.status', $this->status);
        if (is_array($this->attrsSelected) && count($this->attrsSelected)) {
            $criteria->with = array('productAttributes' => array('select' => false, 'together' => true));
            foreach ($this->attrsSelected as $attrId)
                $criteria->compare('"productAttributes_productAttributes".attribute_id', $attrId);
        }

        if (is_array($this->subproductCriteria) && count($this->subproductCriteria)) {
            if (!is_array($criteria->with))
                $criteria->with = array();
            $criteria->with = CMap::mergeArray($criteria->with, array(
                'subProduct' => array(
                    'select' => false,
                    'together' => true,
                ),
            ));
            foreach ($this->subproductCriteria as $attr => $val) {
                if (SubProduct::model()->hasAttribute($attr))
                    $criteria->compare('"subProduct".' . $attr, $val);
            }
        }

        if (is_array($this->id) && isset($this->id['sku'])) {
            $criteria->with = CMap::mergeArray($criteria->with, array(
                'subProduct' => array(
                    'select' => false,
                    'together' => true,
                ),
            ));
            $criteria->addSearchCondition('"subProduct".sku', $this->id['sku'], true, 'AND', 'ILIKE');
            //$criteria->compare('"subProduct".upc_code',$this->id['upc_code']);
        }

        if (is_array($this->subproductAttrsSelected) && count($this->subproductAttrsSelected)) {
            if (!is_array($criteria->with))
                $criteria->with = array();
            $criteria->with = CMap::mergeArray($criteria->with, array(
                'subProduct' => array(
                    'select' => false,
                    'together' => true,
                    'with' => array(
                        'productAttributes' => array('select' => false, 'together' => true, 'alias' => 'subproductAttributes')
                    )
                ),
            ));
            foreach ($this->subproductAttrsSelected as $attrId)
                $criteria->compare('"productAttributes_subproductAttributes".attribute_id', $attrId);
        }
        if (!empty($this->category)) {
            $criteria->with = CMap::mergeArray($criteria->with, array(
                'categories' => array(
                    'select' => false,
                    'together' => true,
                    'joinType' => 'INNER JOIN',
                    'condition' => 'categories.id=:id',
                    'params' => array(':id' => $this->category)
                )
            ));
        }

        if ($merge != null) {
            $criteria->mergeWith($merge);
            if (is_object($merge) && $merge instanceof CDbCriteria)
                $criteria->distinct = $merge->distinct;
        }

        return new CActiveDataProvider(get_class($this), array(
            'criteria' => $criteria,
            'sort' => array(
                'defaultOrder' => 't.id DESC',
            ),
            'pagination' => array(
                'pageSize' => defined('SETTINGS_BO_PAGE_SIZE') ? SETTINGS_BO_PAGE_SIZE : 20,
            ),
        ));
    }

    public function behaviors()
    {
        return array(
            'CTimestampBehavior' => array(
                'class' => 'zii.behaviors.CTimestampBehavior',
                'timestampExpression' => 'date("Y-m-d H:i:s")',
                'createAttribute' => 'creation_datetime',
                'updateAttribute' => 'last_update',
            ),
        );
    }

    public function getAssignedCategoriesAliases()
    {
        $aliases = array();
        foreach($this->categories as $cat)
            $aliases[] = $cat->alias;

        return $aliases;
    }


    public function getSku()
    {
        $subProduct = $this->getCurrentSubproduct();
        if (is_object($subProduct))
            return $subProduct->sku;
        else
            return '';
    }

    public function getLowestPrice()
    {
        /*$consultant_id = 0;
        $consultant = Yii::app()->XService->run('Mlm.Consultant.getSiteOwner');
        if (is_object($consultant))
            $consultant_id = $consultant->id;*/

        $command = Yii::app()->db->createCommand();
        /*$data = $command->select('a.price,a.sale_price')
            ->from(SITE_ID . '_shop_subproduct t')
            ->join(SITE_ID . '_shop_subproduct_price a', 't.id=a.sub_product_id')
            ->join(SITE_ID . '_shop_price_level b', 'a.price_level_id=b.id')
            ->join(SITE_ID . '_mlm_consultant_price_level c', 'b.id=c.price_level_id')
            ->where('t.product_id=:product_id AND c.consultant_id=:consultant_id AND c.status=:status',
            array(':product_id' => $this->id, ':consultant_id' => $consultant_id, ':status' => true))
            ->order('price asc')
            ->queryRow();*/

        $data = $command->select('a.price,a.sale_price')
            ->from(SITE_ID . '_shop_subproduct t')
            ->join(SITE_ID . '_shop_subproduct_price a', 't.id=a.sub_product_id')
            ->join(SITE_ID . '_shop_price_level b', 'a.price_level_id=b.id')
            ->where('t.product_id=:product_id',
            array(':product_id' => $this->id))
            ->order('price asc')
            ->queryRow();

        return $data;
    }


    /*
     *
     */
    public function getPriceData($extract = false)
    {
        //Get the Sub Product of this product
        $subProduct = $this->getCurrentSubproduct();
        if (is_object($subProduct))
            return $subProduct->getPrice($extract);
        return false;
    }

    protected function beforeSave()
    {
        //ensure prefix / in custom url
        if (!empty($this->custom_url))
            $this->custom_url = '/' . ltrim($this->custom_url, '/');

        //convert human datetime format to sql datetime format
        $pattern = Yii::app()->locale->getDateFormat('medium');
        $pattern='MMM d, yyyy';
        $timestamp = CDateTimeParser::parse($this->available_start_date, 'MMM d, yyyy');

        if ($timestamp === false)
            $this->available_start_date = null;
        else
            $this->available_start_date = date('Y-m-d', $timestamp);

        $timestamp = CDateTimeParser::parse($this->available_end_date, $pattern);
        if ($timestamp === false)
            $this->available_end_date = null;
        else
            $this->available_end_date = date('Y-m-d 23:59:00', $timestamp);

        if ($this->on_sale) {
            $timestamp = CDateTimeParser::parse($this->on_sale_start, $pattern);
            if ($timestamp === false)
                $this->on_sale_start = null;
            else
                $this->on_sale_start = date('Y-m-d', $timestamp);

            $timestamp = CDateTimeParser::parse($this->on_sale_end, $pattern);
            if ($timestamp === false)
                $this->on_sale_end = null;
            else
                $this->on_sale_end = date('Y-m-d 23:59:00', $timestamp);
        } else {
            $this->on_sale_start = null;
            $this->on_sale_end = null;
        }

        // check alias exists, if it exists, add num as suffix
        $existedProduct = self::model()->find('alias=:alias', array(':alias' => $this->alias));
        $new_alias = $this->alias;
        if (!$this->isNewRecord && !is_null($existedProduct) && $existedProduct->id != $this->id) {
            $this->alias = $this->alias . '-' . $this->id;
            $new_alias = $this->alias;
            $existedProduct = self::model()->find('alias=:alias', array(':alias' => $new_alias));
        }
        $num = 1;
        while (!is_null($existedProduct) && $existedProduct->id != $this->id) {
            $new_alias = $this->alias . '-' . $num;
            $existedProduct = self::model()->find('alias=:alias', array(':alias' => $new_alias));
            $num++;
        }
        $this->alias = $new_alias;

        return parent::beforeSave();
    }


    /*protected function beforeValidate()
    {
        if ($this->on_sale == true && $this->scenario == 'on_admin') {
            //$this->validatorList->add(CValidator::createValidator('required', $this, 'on_sale_start'));
            if (empty($this->on_sale_start)) {
                $this->addError('on_sale_start', 'Sale start date can not be null if on sale is activate');
            } else {
                if (!empty($this->on_sale_end)) {
                    if (strtotime($this->on_sale_end) < strtotime($this->on_sale_start)) {
                        $this->addError('on_sale_end', 'Sale end date must larger than sale start date');
                    }
                }
            }
        }
        return parent::beforeValidate();
    }*/

    public function getPageDetaisOptions($group = 'main-product-templates')
    {
        //find page by alias
        $model = Page::model()->findByAttributes(array('alias' => $group));
        if (!is_object($model))
            return array();
        $data = Yii::app()->Xservice->run('Cms.Page.buildSubTree', array('id' => $model->id));
        $models = array();
        if (is_array($data) && count($data)) {
            $pageIds = array_keys($data);
            $criteria = new CDbCriteria;
            $criteria->addInCondition('id', $pageIds);
            $models = Page::model()->findAll($criteria);
            if (is_array($models) && count($models))
                $models = CHtml::listData($models, 'alias', 'title');
        }
        return $models;
    }

    public function getCategories()
    {
        $key = 'Shop.models.' . __CLASS__ . '.' . __FUNCTION__ . '.' . $this->id;
        if (($cache = Yii::app()->getComponent('cacheFile')) !== null) {
            if (($categories = $cache->get($key)) !== false) {
                return $categories;
            }
        }
        $categories = $this->categories;
        if (isset($cache))
            $cache->set($key, $categories, defined('SETTINGS_CACHE_EXPIRE') ? SETTINGS_CACHE_EXPIRE : 3600);
        return $categories;
    }

    public function isOnSale()
    {
        $valid = false;
        if ($this->on_sale == true) {
            $now = strtotime('now');
            //every discount need to have a valid date start
            if (!empty($this->on_sale_start) && strtotime($this->on_sale_start) <= $now) {
                $valid = true;
                //If the on sale end is not provided,it's mean last forever,else,we will check
                if (!empty($this->on_sale_end)) {
                    if (strtotime($this->on_sale_end) < $now)
                        $valid = false;
                }
            }
        }
        return $valid;
    }

    public function getImage($width = 100, $height = 100)
    {
        $subProduct = $this->getCurrentSubproduct();
        $img = '#';
        if (!$subProduct && count($this->subProduct))
            $subProduct = $this->subProduct[0];
        if (is_object($subProduct))
            $img = $subProduct->getImage($width, $height);
        return $img;
    }

    public function getProductItems($onlyFirstImage = false, $options = array())
    {
        //only options for image or get only get all images or get images and video
        $resize = is_array($options) && isset($options['resize']) ? CPropertyValue::ensureBoolean($options['resize']) : true;
        $onlyImage = is_array($options) && isset($options['onlyImage']) ? CPropertyValue::ensureBoolean($options['onlyImage']) : false;
        $width = is_array($options) && isset($options['width']) ? CPropertyValue::ensureInteger($options['width']) : 100;
        $height = is_array($options) && isset($options['height']) ? CPropertyValue::ensureInteger($options['height']) : 100;

        $gallery = $this->galleryProduct;
        $baseUrl = Yii::app()->assetManager->publish(Yii::getPathOfAlias('Gallery.components.widgets.assets.galleries.*'));
        $noImage = $baseUrl.'/images/no_image.jpg';
        if (is_object($gallery)) {
            if ($onlyFirstImage) {
                $img = $gallery->getFirstImage();
                if ($img !== false) {
                    Yii::import('application.modules.Gallery.components.GalleryHelper');
                    return $resize ? GalleryHelper::renderThumb($img, $width, $height) : $img;
                } else
                    return $noImage;
            } else {
                $data = array();
                $items = $gallery->getGalleryItems(false, $onlyImage);
                if (is_array($items) && count($items)) {
                    Yii::import('application.modules.Gallery.components.GalleryHelper');
                    foreach ($items as $src) {
                        if (in_array(strtolower(strtolower(CFileHelper::getExtension($src))), array('jpg', 'gif', 'png', 'jpeg'))) {
                            $data[] = $resize ? GalleryHelper::renderThumb($src, $width, $height) : $src;
                        } else {
                            //video format
                            $data[] = $src;
                        }
                    }
                }
                return $data;
            }
        } else {
            if ($onlyFirstImage) {
                return $noImage;
            } else
                return array($noImage);
        }
    }

    public function getUrl()
    {
        $categories = $this->categories;
        $url = "#";
        if (is_array($categories) && count($categories)) {
            $category = array_shift($categories);
            $url = $category->alias . '/' . $this->alias . '.html';
        }
        return $url;
    }

    public function inStock()
    {
        $subProduct = $this->getCurrentSubproduct();
        $inStock = false;
        if (is_object($subProduct)) {
            $inStock = $subProduct->getStock();
            if ($inStock == 0)
                $inStock = false;
        }
        return $inStock;
    }

    public function getCurrentSubproduct($force = false, $preview = false)
    {
        if ($this->_currentSubproduct === null || $force) {
            $condition = '"subProduct".status=true';
            $params = array();
            $sku = '';
            //lookup sku or alias
            //bugs when product use url /product-[sku:\d+].html or /[sku:\d+]-[product_alias].html
            $urlArr = parse_url(Yii::app()->request->hostInfo . Yii::app()->request->url);
            if (is_array($urlArr) && isset($urlArr['query'])) {
                parse_str($urlArr['query'], $output);
                if (is_array($output) && isset($output['sku']))
                    $sku = $output['sku'];
            }
            if (empty($sku))
                $sku = Yii::app()->request->getQuery('sku', '');
            if (!empty($sku)) {
                if ($preview || isset($_GET['product_preview']))
                    $condition = '1=1';
                $condition .= ' AND sku = :sku';
                $params = array(
                    'sku' => $sku,
                );
            } else {
                if ($preview || isset($_GET['product_preview']))
                    $condition = '1=1';
                $condition .= ' AND "subProduct".id = (
   SELECT sub_product_id FROM ' . SITE_ID . '_shop_subproduct_price
   INNER JOIN '.SITE_ID.'_shop_subproduct sub ON sub.id = sub_product_id
   WHERE sub.product_id = ' . $this->id . ' ORDER BY price LIMIT 1)';
            }
            $rows = $this->subProduct(array(
                'condition' => $condition,
                'params' => $params,
                'limit' => 1,
            ));
            //Yii::app()->end();
            if (is_array($rows) && count($rows)) {
                $this->_currentSubproduct = current($rows);
            }
//            if (!is_object($this->_currentSubproduct))
//                throw new CHttpException(404, 'Not found product');
        }
        return $this->_currentSubproduct;
    }

    public function searchCustom($checkAvailable=false)
    {
        $criteria = new CDbCriteria();
        $criteria->with = array();
        /*$criteria->addCondition('t.status = true');
        $criteria->addCondition('t.in_stock = false');*/
        if ($this->status != '')
        {
            if ($this->status == '1')
                $criteria->addCondition('t.status = true');
            else
                $criteria->addCondition('t.status = false');
        }
        if ($this->in_stock != '')
        {
            if ($this->in_stock == '1')
                $criteria->addCondition('t.in_stock = true');
            else
                $criteria->addCondition('t.in_stock = false');
        }

        if ($checkAvailable==true)
        {
            $criteria->addCondition('( (NOW() >= t.available_start_date AND NOT t.available_start_date IS NULL) OR t.available_start_date IS NULL)');
            $criteria->addCondition('( (NOW() <= t.available_end_date AND NOT t.available_end_date IS NULL) OR t.available_end_date IS NULL)');
        }
        $criteria->addSearchCondition('t.name', $this->name, true, 'AND', 'ILIKE');

        if (!empty($this->category)) {
            $criteria->with = CMap::mergeArray($criteria->with, array(
                'categories' => array(
                    'select' => false,
                    'together' => true,
                    'joinType' => 'INNER JOIN',
                    'condition' => 'categories.id=:id',
                    'params' => array(':id' => $this->category)
                )
            ));
        }

        if (is_array($this->id) && isset($this->id['sku']))
        {
            $criteria->with = CMap::mergeArray($criteria->with, array(
                'subProduct' => array(
                    'select' => false,
                    'together' => true,
                ),
            ));
            $criteria->addSearchCondition('"subProduct".sku', $this->id['sku'], true, 'AND', 'ILIKE');
        }

        return new CActiveDataProvider(get_class($this), array(
            'criteria' => $criteria,
            'sort' => array(
                'defaultOrder' => 't.id DESC',
            ),
            'pagination' => array(
                'pageSize' => defined('SETTINGS_BO_PAGE_SIZE') ? SETTINGS_BO_PAGE_SIZE : 20,
            ),
        ));
    }

    public function searchByFeaturedProduct($selectedProductId='')
    {
        $criteria = new CDbCriteria();
        $criteria->with = array();

        $selectedProductId = trim($selectedProductId);
        if ($selectedProductId != '')
            $criteria->addCondition('((SELECT COUNT(*) FROM "tagrem_serta_shop_featured_product" "fp" WHERE fp.product_id = t.id) = 0 OR t.id = '.$selectedProductId.')');
        else
            $criteria->addCondition('(SELECT COUNT(*) FROM "tagrem_serta_shop_featured_product" "fp" WHERE fp.product_id = t.id) = 0');

        if ($this->status != '')
        {
            if ($this->status == '1')
                $criteria->addCondition('t.status = true');
            else
                $criteria->addCondition('t.status = false');
        }

        $criteria->addSearchCondition('t.name', $this->name, true, 'AND', 'ILIKE');

        if (!empty($this->category)) {
            $criteria->with = CMap::mergeArray($criteria->with, array(
                'categories' => array(
                    'select' => false,
                    'together' => true,
                    'joinType' => 'INNER JOIN',
                    'condition' => 'categories.id=:id',
                    'params' => array(':id' => $this->category)
                )
            ));
        }

        return new CActiveDataProvider(get_class($this), array(
            'criteria' => $criteria,
            'sort' => array(
                'defaultOrder' => 't.id DESC',
            ),
            'pagination' => array(
                'pageSize' => defined('SETTINGS_BO_PAGE_SIZE') ? SETTINGS_BO_PAGE_SIZE : 30,
            ),
        ));
    }
    
    public function getProductAttributeByGroupName($group_name)
    {
        $criteria = new CDbCriteria;
        $criteria->addSearchCondition('name', $group_name, false, 'AND', 'ILIKE');
        $criteria->addCondition('is_sub = false');
        $attrGroup = AttributeGroup::model()->find($criteria);
        if ($attrGroup == null) 
            return null;
            
        $criteria = new CDbCriteria();
        $criteria->join = 'INNER JOIN "'.SITE_ID.'_shop_product_attribute" "pa" ON pa.attribute_id = t.id';
        $criteria->condition = 'pa.product_id=:proId AND pa.group_id=:groupId';
        $criteria->params = array(':proId'=>$this->id,':groupId'=>$attrGroup->id);
        $attr = Attribute::model()->find($criteria);
        return $attr;
    }
}